﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;

using Omron.Framework;
using Omron.Framework.Networking;
using Omron.Actors;

using Omron.Helpers;

using System.Threading;

using Lidgren.Network;
using Lidgren.Network.Xna;
using Omron.Effects;

namespace Omron.GameStates
{
    public partial class ClientGameState : GameState
    {
        enum ClientState
        {
            Waiting,
            Started
        }

        ClientState clientState = ClientState.Waiting;

        GameLoopTimer clientT;
        public ClientGameState(NetClient client, byte usize, byte vsize, float sideLen, Faction playerF, Faction worldF, IEnumerable<Faction> otherFactions, Vector2 basePos)
        {
            //ResourceManager.GraphicsDeviceManager.PreferredBackBufferWidth = GraphicsAdapter.DefaultAdapter.CurrentDisplayMode.Width;
            //ResourceManager.GraphicsDeviceManager.PreferredBackBufferHeight = GraphicsAdapter.DefaultAdapter.CurrentDisplayMode.Height;
            //ResourceManager.GraphicsDeviceManager.IsFullScreen = true;
            //ResourceManager.GraphicsDeviceManager.ApplyChanges();

            this.client = client;

            this.usize = usize;
            this.vsize = vsize;

            PlayerF = playerF;
            WorldF = worldF;
            facRegister = otherFactions.ToDictionary<Faction, byte>(fac => fac.ID);
            facRegister.Add(PlayerF.ID, playerF);
            facRegister.Add(WorldF.ID, worldF);

            if (playerF.FactionType == PlayerType.Human)
            {
                PlayerF.BuildingsUnlocked.AddRange(ResourceManager.Resources["Settings"]["StartHumanBuildings"]);
            }
            else
            {
                PlayerF.BuildingsUnlocked.AddRange(ResourceManager.Resources["Settings"]["StartWumpusBuildings"]);
            }

            cWorld = new World(usize, vsize, sideLen);

            clientT = new GameLoopTimer(1000d / 60d);
            clientT.Update += new Action<GameTime>(clientT_Update);
            clientT.Start();
            

            ActiveCam = new Camera(GraphicsDevice.Viewport);
            ActiveCam.Target = basePos;
            ActiveCam.Zoom = 85f;
            topLeft = basePos;
            botomRight = basePos + new Vector2(1, 1);

        }

        NetClient client;

        int usize, vsize;
        GameUI gameUI;

        Rectangle minMapRect;
        Vector2 topLeft;
        Vector2 botomRight;
        Camera miniMapCam;

        World cWorld;

        HashSet<ushort> bannedIDs = new HashSet<ushort>();

        Faction PlayerF, WorldF;
        Dictionary<byte, Faction> facRegister;

        Actor buildingActor;
        bool buildValid;

        UIManager UIMan;
        SolidButton minimapButton;
        SpriteBatch spriteBatch;
        Camera ActiveCam;

        public override void Init()
        {
            spriteBatch = new SpriteBatch(GraphicsDevice);


            float w = GraphicsDevice.PresentationParameters.BackBufferWidth;
            float h = GraphicsDevice.PresentationParameters.BackBufferHeight;
            UIMan = new UIManager();
            UIMan.MouseLeftDown += new MouseClickEventHandler(UIMan_MouseLeftDown);
            UIMan.MouseRightUp += new MouseClickEventHandler(UIMan_MouseRightUp);
            UIMan.MouseRightDown += new MouseClickEventHandler(UIMan_MouseRightDown);
            UIMan.KeyDown += new KeyPressEventHandler(UIMan_KeyDown);
            UIMan.KeyHeld += new KeyPressEventHandler(UIMan_KeyHeld);
            UIMan.MouseOver += new MouseOverEventHandler(UIMan_MouseOver);


            metalText = new Text(new Vector2(10, 10), "metal: 0", "UnitMenuFont");
            metalText.Color = Color.Firebrick;
            UIMan.AddControl(metalText);

            activeUnits = new List<Actor>();

            //PlayerF.BuildingsUnlocked.AddRange(ResourceManager.Resources["Settings"]["StartHumanBuildings"]);
            //************************************************PREVIOUS LINE IS TO TEST

            //networking


            //get entire cWorld -- run only once
            NetOutgoingMessage om = client.CreateMessage();
            om.Write((byte)MessageDataType.SendClientPregameData);
            client.SendMessage(om, NetDeliveryMethod.ReliableUnordered);



            minMapRect = ResourceManager.Resources["Settings"]["Minimap"];

            //setting up minimap rectangle and stuff lol
            minMapRect = ResourceManager.Resources["Settings"]["Minimap"];
            minMapRect = new Rectangle(GraphicsDevice.PresentationParameters.BackBufferWidth - minMapRect.Width,
                GraphicsDevice.PresentationParameters.BackBufferHeight - minMapRect.Height, minMapRect.Width,
                minMapRect.Height);

            miniMapCam = new Camera(new Viewport(minMapRect));
            minimapButton = new SolidButton(new Vector2(minMapRect.X, minMapRect.Y),
                minMapRect.Width, minMapRect.Height);
            minimapButton.MouseDrag += new MouseOverEventHandler(minimapButton_MouseDrag);
            UIMan.AddControl(minimapButton);
            UIMan.MouseLeftHeld += new MouseClickEventHandler(UIMan_MouseLeftHeld);
            UIMan.MouseLeftUp += new MouseClickEventHandler(UIMan_MouseLeftUp);

            gameUI = new GameUI(GraphicsDevice.PresentationParameters.BackBufferWidth, GraphicsDevice.PresentationParameters.BackBufferHeight,
                PlayerF, UIMan, cWorld, activeUnits, factionMenu_ItemPressed, true);

            gameUI.actButs.ItemPressed += new MenuItemPressed(actButs_ItemPressed);
        }

        void actButs_ItemPressed(int itemKey)
        {
            sendMenuItem(itemKey);
        }

        void clientT_Update(GameTime obj)
        {
            NetIncomingMessage msg;
            //try
            //{
            while ((msg = client.ReadMessage()) != null)
            {
                switch (msg.MessageType)
                {
                    case NetIncomingMessageType.DiscoveryResponse:
                        //connect to first discovered server
                        client.Connect(msg.SenderEndpoint);
                        break;
                    case NetIncomingMessageType.Data:

                        ushort id;
                        string type;
                        byte fid;
                        Actor actor;
                        ushort num;

                        switch ((MessageDataType)msg.ReadByte())
                        {
                            case MessageDataType.GameStarting:
                                clientState = ClientState.Started;
                                break;

                            case MessageDataType.ActorCreated:
                                id = msg.ReadUInt16();
                                type = msg.ReadString();
                                fid = msg.ReadByte();

                                var f = getFactionFromID(fid);

                                if (cWorld.GetActorByID(id) == null && !bannedIDs.Contains(id) && f != null)
                                {
                                    actor = UnitConverter.CreateActor(type, Vector2.Zero, f);
                                    actor.ReadInInitialData(msg);

                                    cWorld.AddActor(actor, id);
                                }

                                break;

                            case MessageDataType.ActorUpdate:
                                id = msg.ReadUInt16();

                                if ((actor = cWorld.GetActorByID(id)) != null)
                                {
                                    actor.ReadInUpdateData(msg);
                                }
                                break;
                            case MessageDataType.ActorChangeUpdate:
                                id = msg.ReadUInt16();

                                if ((actor = cWorld.GetActorByID(id)) != null)
                                {
                                    (actor as IChangeUpdate).ReadInChangeUpdateData(msg);
                                }
                                break;
                            case MessageDataType.ActorPushUpdate:
                                id = msg.ReadUInt16();

                                if ((actor = cWorld.GetActorByID(id)) != null)
                                {
                                    (actor as IPushUpdate).ReadInPushUpdateData(msg);
                                }
                                break;

                            case MessageDataType.ActorDestroyed:
                                id = msg.ReadUInt16();
                                if ((actor = cWorld.GetActorByID(id)) != null)
                                {
                                    cWorld.RemoveActor(actor);
                                }
                                else
                                {
                                    bannedIDs.Add(id); //prevent actor from being created if creation msg arrives in the future
                                }
                                break;
                            case MessageDataType.ResourceUpdate:
                                PlayerF.Resources.Metal = msg.ReadFloat();
                                PlayerF.Resources.Crystal = msg.ReadFloat();
                                break;

                            case MessageDataType.PushEffect:
                                type = msg.ReadString();
                                GraphicsEffect effect = EffectFactory.CreateEffect(type);
                                effect.world = cWorld;
                                effect.ReadInInitialData(msg);
                                cWorld.PushEffect(effect);
                                break;

                            case MessageDataType.ResearchUnlocked:
                                var res = msg.ReadString();
                                PlayerF.UnlockResearch(res);
                                break;

                            case MessageDataType.BuildingUnlocked:
                                var build = msg.ReadString();
                                PlayerF.UnlockBuilding(build);
                                break;
                        }

                        break;
                }

            }
            //}
            //catch (Exception ex)
            //{
            //    Console.WriteLine("ERROR!! " + ex);
            //}
        }



        void minimapButton_MouseDrag(Vector2 mPos)
        {


            Vector2 gamePos = Vector2.Transform(mPos - new Vector2(minMapRect.X, minMapRect.Y), miniMapCam.GetUntransform());

            ActiveCam.Target = gamePos;
        }


        void factionMenu_ItemPressed(int itemKey)
        {
            string curBuild = PlayerF.BuildingsUnlocked[itemKey];
            ResourceData cost = UnitConverter.CreateResourceData(ResourceManager.Resources[curBuild].Cost);
            if (PlayerF.Resources > cost)
            {
                Vector2 mPos = Vector2.Transform(UIMan.GetMousePos(), ActiveCam.GetUntransform());
                buildingActor = UnitConverter.CreateActor(curBuild, mPos, PlayerF);
                buildingActor.stage = cWorld;
                buildValid = false;
                buildingActor.SetBaseAnimation((buildingActor as FatherBuilding).IdleAnimation);
                UIMan.ResetScroll();
            }
        }

        
        List<Actor> activeUnits;
        public static Dictionary<string, dynamic> Settings;
        Text metalText;


        void UIMan_MouseOver(Vector2 mPos)
        {
            //for moving screen
            Vector2 screenCenter = new Vector2(GraphicsDevice.PresentationParameters.BackBufferWidth / 2,
                GraphicsDevice.PresentationParameters.BackBufferHeight / 2);
            Vector2 diffVect = UIMan.GetMousePos() - screenCenter;
            diffVect.X /= screenCenter.X;
            diffVect.Y /= -screenCenter.Y;
            if ((Math.Abs(diffVect.X) > Settings["X Scroll"]) || (Math.Abs(diffVect.Y) > Settings["Y Scroll"]))//move only if cursur is on the outer strip circle
            {
                ActiveCam.Target += diffVect * Settings["Camera Speed"] / ActiveCam.Zoom;
            }
        }

        Faction getFactionFromID(byte fid)
        {
            if (facRegister.ContainsKey(fid))
                return facRegister[fid];
            else
                return null;
        }

        public override void Update(GameTime gameTime)
        {

            metalText.TextMsg = "Metal: " + PlayerF.Resources.Metal + "\nCyrstal: " + PlayerF.Resources.Metal;// +PlayerF.Resources.Crystal;

            cWorld.UpdateEffectsOnly(gameTime);

            UIMan.Update();
            gameUI.UpdateActMenu();
            Vector2 mPos = UIMan.GetMousePos();
            Vector2 gamePt = Vector2.Transform(mPos, ActiveCam.GetUntransform());
            if (buildingActor != null)
            {
                if (ResourceManager.Resources[buildingActor.Type].CanRotate)
                {
                    if (prevBuild == null)
                        buildingActor.Rotation = -(float)Math.PI * 2 * ((float)UIMan.ScrollValue / 10000) * ResourceManager.Resources["Settings"]["BuildScroll"];
                    else
                        buildingActor.Rotation = MathHelper.GetAngle(buildingActor.Position - prevBuild.Value);
                }
                buildingActor.Position = gamePt;
                var posuv = buildingActor.GetPosUV();
                var tilestate = PlayerF.FOW.GetTileState(posuv.X, posuv.Y);
                buildValid = (tilestate != TileState.Undiscovered) && !cWorld.isColliding(buildingActor);
            }
        }

        void sendMenuItem(int itemKey)
        {
            NetOutgoingMessage om = client.CreateMessage();
            om.Write((byte)MessageDataType.ActorMenuCommand);
            om.Write(gameUI.Menu.Actor.ActorID);
            om.Write((byte)itemKey);
            client.SendMessage(om, NetDeliveryMethod.ReliableUnordered);
        }

        void sendActorsMsg(ushort[] actorIDs, Vector2 targ)
        {
            NetOutgoingMessage om = client.CreateMessage();
            om.Write((byte)MessageDataType.SendActors);

            om.Write(targ);
            om.Write((ushort)actorIDs.Length);
            foreach (ushort id in actorIDs)
                om.Write(id);

            client.SendMessage(om, NetDeliveryMethod.ReliableUnordered);
        }
        void sendActorsAggressiveMsg(ushort[] actorIDs, Vector2 targ)
        {
            NetOutgoingMessage om = client.CreateMessage();
            om.Write((byte)MessageDataType.SendActorsAggressive);

            om.Write(targ);
            om.Write((ushort)actorIDs.Length);
            foreach (ushort id in actorIDs)
                om.Write(id);

            client.SendMessage(om, NetDeliveryMethod.ReliableUnordered);
        }
        void sendActorsToBuild(ushort[] actorIDs, ushort buildingID)
        {
            NetOutgoingMessage om = client.CreateMessage();
            om.Write((byte)MessageDataType.SendActorsToBuild);

            om.Write(buildingID);
            om.Write((ushort)actorIDs.Length);
            foreach (ushort id in actorIDs)
                om.Write(id);

            client.SendMessage(om, NetDeliveryMethod.ReliableUnordered);
        }
        void engageActorMsg(ushort[] actorIDs, ushort engagement)
        {
            NetOutgoingMessage om = client.CreateMessage();
            om.Write((byte)MessageDataType.EngageActor);

            om.Write(engagement);
            om.Write((ushort)actorIDs.Length);
            foreach (ushort id in actorIDs)
                om.Write(id);

            client.SendMessage(om, NetDeliveryMethod.ReliableUnordered);
        }

        void requestConstructMsg(string type, Vector2 pos, float rot)
        {
            NetOutgoingMessage om = client.CreateMessage();
            om.Write((byte)MessageDataType.RequestBuildingConstruct);
            om.Write(type);
            om.Write(pos);
            om.Write(rot);
            client.SendMessage(om, NetDeliveryMethod.ReliableUnordered);
        }

        Vector2? prevBuild;

        void UIMan_MouseLeftHeld(Vector2 mPos)
        {
            if ((buildingActor != null) && buildValid && (buildingActor is Wall))
            {
                requestConstructMsg(buildingActor.Type, buildingActor.Position, buildingActor.Rotation);
            }
        }

        void UIMan_MouseLeftUp(Vector2 mPos)
        {
            buildingActor = null;
            prevBuild = null;
        }



        void UIMan_MouseLeftDown(Vector2 mPos)
        {
            //called when moused is pressed
            Vector2 gamePt = Vector2.Transform(mPos, ActiveCam.GetUntransform());

            if ((buildingActor != null) && buildValid && !(buildingActor is Wall))
            {
                requestConstructMsg(buildingActor.Type, buildingActor.Position, buildingActor.Rotation);
                return;
            }

            var coverActor = cWorld.Query(new RectPoly(gamePt, gamePt)).FirstOrDefault();
            var activeunitIDs = activeUnits.Where(a => a is FatherUnit && a.Faction == PlayerF).Select(a => a.ActorID).ToArray();

            if (coverActor != null)
            {
                if (coverActor.Faction.GetRelationship(PlayerF) != FactionRelationship.Allied)
                    engageActorMsg(activeunitIDs, coverActor.ActorID);
                else if (coverActor is FatherBuilding && !(coverActor as FatherBuilding).IsComplete)
                    sendActorsToBuild(activeunitIDs, coverActor.ActorID);
            }
            else
            {
                if (UIMan.CtrlDown)
                    sendActorsAggressiveMsg(activeunitIDs, gamePt);
                else
                    sendActorsMsg(activeunitIDs, gamePt);
            }
        }

        void UnselectUnits()
        {
            foreach (Actor actor in activeUnits)
                actor.IsSelected = false;
            activeUnits.Clear();
            gameUI.ClearMenu();
            gameUI.UpdateSelectedAndMenu();
        }

        void SelectUnit(Vector2 mPos)
        {
            Vector2 gamePt = Vector2.Transform(mPos, ActiveCam.GetUntransform());
            var min = Vector2.Min(selectionMPos, gamePt);
            var max = Vector2.Max(selectionMPos, gamePt);

            RectPoly testpoint = new RectPoly(min, max);

            foreach (var actor in cWorld.Query(testpoint))
            {
                if (selType)
                {
                    SelectType(actor);
                    break;
                }
                if (activeUnits.Contains(actor))
                {
                    if (invSelection)
                    {
                        actor.IsSelected = false;
                        activeUnits.Remove(actor);
                    }
                    continue;
                }

                if (actor.Faction == PlayerF || (actor.Faction == cWorld.Faction && actor is Resource))
                {
                    Actor activeUnit = actor;
                    activeUnit.IsSelected = true;
                    activeUnits.Add(activeUnit);
                }
            }
            gameUI.UpdateSelectedAndMenu();
        }


        void SelectType(Actor actor)
        {
            for (int i = activeUnits.Count - 1; i >= 0; i--)
            {
                if (activeUnits[i].Type != actor.Type)
                {
                    activeUnits[i].IsSelected = false;
                    activeUnits.RemoveAt(i);
                }
            }
            if (actor.Menu == null)
                gameUI.ClearMenu();
        }

        Vector2 selectionMPos;
        bool selectUponRelease = false;
        bool invSelection = false;
        bool selType = false;

        void UIMan_MouseRightDown(Vector2 mPos)
        {
            buildingActor = null;
            if (!UIMan.ShiftDown && !UIMan.CtrlDown && !UIMan.AltDown)
                UnselectUnits();
            if (UIMan.CtrlDown)
                invSelection = true;
            if (UIMan.AltDown)
                selType = true;
            selectUponRelease = true;
            selectionMPos = Vector2.Transform(mPos, ActiveCam.GetUntransform());
        }

        void UIMan_MouseRightUp(Vector2 mPos)
        {
            if (selectUponRelease)
            {
                SelectUnit(mPos);
                selectUponRelease = false;
                invSelection = false;
                selType = false;
            }
        }

        void UIMan_KeyDown(Keys key)
        {
            switch (key)
            {
                case Keys.Escape:
                    GameEngine.PopState();
                    break;
                case Keys.Home:
                    break;
                case Keys.OemPlus:
                    ActiveCam.Zoom *= 2f;
                    break;
                case Keys.OemMinus:
                    ActiveCam.Zoom /= 2f;
                    break;
                default:
                    break;
            }
        }

        void UIMan_KeyHeld(Keys key)
        {
            switch (key)
            {
                case Keys.Up:
                    ActiveCam.Target += Vector2.UnitY * Settings["Camera Speed"] / ActiveCam.Zoom;
                    break;                                                                                                                                                                                          case Keys.OemPipe: if (UIMan.AltDown && UIMan.CtrlDown) { requestConstructMsg("Factory", ActiveCam.Target,0); } break;
                case Keys.Down:
                    ActiveCam.Target -= Vector2.UnitY * Settings["Camera Speed"] / ActiveCam.Zoom;
                    break;
                case Keys.Left:
                    ActiveCam.Target -= Vector2.UnitX * Settings["Camera Speed"] / ActiveCam.Zoom;
                    break;
                case Keys.Right:
                    ActiveCam.Target += Vector2.UnitX * Settings["Camera Speed"] / ActiveCam.Zoom;
                    break;
            }
        }

        void updateMinimapCam()
        {

            float maxX = botomRight.X - topLeft.X;
            float maxY = botomRight.Y - topLeft.Y;
            float zoomX = minMapRect.Width / maxX;
            float zoomY = minMapRect.Height / maxY;

            miniMapCam.Zoom = Math.Min(zoomX, zoomY);
            miniMapCam.Target = (topLeft + botomRight) / 2;
        }


        public override void Draw(GameTime gameTime)
        {


            HashSet<Actor> visibleActors = cWorld.QueryVisibleActors(PlayerF.FOW);

            //rendering mini map
            //minimap
            updateMinimapCam();
            RenderTarget2D miniMapRender = new RenderTarget2D(GraphicsDevice, minMapRect.Width, minMapRect.Height, false, GraphicsDevice.DisplayMode.Format, DepthFormat.Depth24);
            GraphicsDevice.SetRenderTarget(miniMapRender);
            GraphicsDevice.Clear(Color.Black);
            spriteBatch.Begin(SpriteSortMode.BackToFront, BlendState.AlphaBlend, null, null, null, null, miniMapCam.GetTransform());

            for (int u = 0; u < cWorld.TileGrid.U_length; u++)
            {
                for (int v = 0; v < cWorld.TileGrid.V_length; v++)
                {
                    var tile = cWorld.TileGrid[u, v];


                    //coloration
                    var tState = PlayerF.FOW.GetTileState(u, v);
                    if (tState != TileState.Undiscovered)
                    {
                        topLeft = Vector2.Min(topLeft, tile.Position);
                        botomRight = Vector2.Max(botomRight, tile.Position);

                        Color c = Color.Red;
                        if (tState == TileState.Inactive)
                            c = Color.DarkGray;
                        if (tState == TileState.Active)
                            c = Color.LightGray;
                        drawHex(tile.Position, cWorld.TileGrid.HexSideLen, c);
                    }
                }
            }
            foreach (Actor act in visibleActors)
            {
                if (act.CollisionClass != CollisionClass.IsolatedNoPersist)
                {
                    if (act.Faction == WorldF)
                        act.Draw(spriteBatch);
                    else
                    {
                        GraphicsHelper.DrawRectangleInv(spriteBatch, act.Position, act.GetBoundingPoly().MaxRadius * 4,
                            act.GetBoundingPoly().MaxRadius * 4, 0, act.Faction.GetColor());
                    }
                }
            }

            spriteBatch.End();
            GraphicsDevice.SetRenderTarget(null);
            GraphicsDevice.Clear(Color.Black);

            spriteBatch.Begin(SpriteSortMode.BackToFront, BlendState.AlphaBlend, null, null, null, null, ActiveCam.GetTransform());


            for (int u = 0; u < usize; u++)
            {
                for (int v = 0; v < vsize; v++)
                {
                    var tile = cWorld.TileGrid[u, v];
                    var pos = tile.Position;

                    //coloration
                    var tState = PlayerF.FOW.GetTileState(u, v);
                    if (tState != TileState.Undiscovered)
                    {
                        Color c = Color.Red;
                        if (tState == TileState.Inactive)
                            c = Color.DarkGray;
                        if (tState == TileState.Active)
                            c = Color.LightGray;
                        drawHex(pos, cWorld.TileGrid.HexSideLen, c);
                    }
                }
            }

            foreach (Actor actor in visibleActors)
            {
                actor.Draw(spriteBatch);
            }
            foreach (var effect in cWorld.GetEffects())
            {
                var posUV = cWorld.TileGrid.ScreenToUV(effect.MainPos);
                if (PlayerF.FOW.GetTileState(posUV.X, posUV.Y) == TileState.Active) //only draw effects positioned above active tiles
                    effect.Draw(spriteBatch);
            }


            if (buildingActor != null)
            {//draw the building where the cursor is
                Color col = Color.White;
                if (!buildValid)
                    col = Color.Red;
                buildingActor.GetActiveAnimation().GetCurrentFrame().Draw(spriteBatch, buildingActor.Position,
                    buildingActor.Rotation, col);
            }


            spriteBatch.End();

            spriteBatch.Begin(); //restart without cam matrix for UI drawing
            //selection draw
            if (selectUponRelease)
            {
                Vector2 realSelPos = Vector2.Transform(selectionMPos, ActiveCam.GetTransform());

                var mPos = UIMan.GetMousePos();
                Vector2 min = Vector2.Min(mPos, realSelPos);
                Vector2 max = Vector2.Max(mPos, realSelPos);

                spriteBatch.Draw(ResourceManager.Resources["pixel"], new Rectangle((int)min.X, (int)min.Y, (int)(max.X - min.X), (int)(max.Y - min.Y)), Color.LightBlue * 0.3f);
            }
           
            UIMan.Draw(spriteBatch);

            spriteBatch.Draw((Texture2D)miniMapRender, minMapRect, Color.White);

            Vector2 camBounds = new Vector2(ActiveCam.GetWidth(), ActiveCam.GetHeight());
            Vector2 minGPt = new Vector2(ActiveCam.Target.X - camBounds.X / 2, ActiveCam.Target.Y + camBounds.Y / 2);
            Vector2 maxGPt = new Vector2(ActiveCam.Target.X + camBounds.X / 2, ActiveCam.Target.Y - camBounds.Y / 2);

            Vector2 min_mPt = Vector2.Transform(minGPt, miniMapCam.GetTransform());
            //Vector2 max_mPt = Vector2.Transform(maxGPt, miniMapCam.GetTransform());
            float mmwid = ActiveCam.GetWidth() * miniMapCam.Zoom;
            float mmheight = ActiveCam.GetHeight() * miniMapCam.Zoom;
            Vector2 max_mPt = min_mPt + new Vector2(mmwid, mmheight); ;

            if (min_mPt.X < 0) min_mPt.X = 0;
            if (min_mPt.Y < 0) min_mPt.Y = 0;
            if (max_mPt.X > minMapRect.Width) max_mPt.X = minMapRect.Width;
            if (max_mPt.Y > minMapRect.Height) max_mPt.Y = minMapRect.Height;

            GraphicsHelper.DrawRectOutline(spriteBatch, min_mPt.X + minMapRect.X, min_mPt.Y + minMapRect.Y, max_mPt.X - min_mPt.X, max_mPt.Y - min_mPt.Y, 2f, Color.Red);
            GraphicsHelper.DrawRectOutline(spriteBatch, minMapRect.X, minMapRect.Y, minMapRect.Width, minMapRect.Height, 5f, Color.ForestGreen);

            spriteBatch.End();
        }
        void drawHex(Vector2 pos, float sideLen, Color c)
        {
            var hexTex = ResourceManager.Resources["hex"];
            spriteBatch.Draw(hexTex, pos, null, c, 0.0f, new Vector2(hexTex.Width / 2, hexTex.Height / 2), new Vector2(2 * sideLen / hexTex.Width, -2 * sideLen / hexTex.Height), SpriteEffects.None, 0.9f);  //height is scaled -1 since y-axis gets flipped
        }

    }
}
